package com.smsc.headend.task.engine.handler.impl.generalparam;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Preconditions;
import com.smsc.headend.common.enums.errorcode.TaskHandlerErrorCode;
import com.smsc.headend.common.utils.CosemUtils;
import com.smsc.headend.module.asset.dto.VendingParameterMessageDto;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.AppName;
import com.smsc.headend.module.common.entity.ScalerUnit;
import com.smsc.headend.module.data.dto.DLMSSubDataItemDTO;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.data.dto.TaskDataDTO;
import com.smsc.headend.module.data.entity.RdModeSwitchData;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.data.query.ModelDataItemQueryItem;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.protocol.cosem.enums.Unit;
import com.smsc.headend.module.protocol.cosem.ic.TokenGateway;
import com.smsc.headend.module.report.entity.LogModeSwitchHisSub;
import com.smsc.headend.module.scheme.entity.ConfigScheduleTask;
import com.smsc.headend.module.task.consts.TaskKafkaTopic;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.dto.TaskResult;
import com.smsc.headend.module.task.enums.DeviceActionType;
import com.smsc.headend.module.task.enums.SubTaskStatus;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.handler.TaskHandler;
import com.smsc.headend.task.engine.mapper.RdModeSwitchDataMapper;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.utils.CustomCosemUtil;
import gurux.dlms.enums.ObjectType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wxh
 * @date 2021/4/20 14:06
 */
@Slf4j
public class ReadGeneralParamHandler implements TaskHandler {
    @Autowired
    CosemXmlService cosemXmlService;
    @Autowired
    TaskDAO taskDAO;
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    RdModeSwitchDataMapper rdModeSwitchDataMapper;
    @Autowired
    KafkaTemplate kafkaTemplate;

    @Override
    public int handle(Task task, AtomicTask atomicTask, DeviceData deviceData, String actionResult) throws UDISTaskHandlerException {
        if (!(deviceData instanceof CosemData)) {
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.DEVICE_DATA_TYPE_NOT_SUPPORT.toString());
        }
        Meter meter = assetManagementService.getMeterById(task.getMeterId());
        CosemData cosemData = (CosemData) deviceData;
        Map<String, Object> param = getParameterMap(task, atomicTask);
        Long subDataItemId = Long.valueOf(String.valueOf(param.get("subDataItemId")));
        List<DataItemDTO> dataItemDTOS = getModelDataItemCosems(meter.getModelId(), Lists.newArrayList(subDataItemId), DeviceActionType.Get.getCode());
        if (CollUtil.isEmpty(dataItemDTOS)) {
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.NO_TASK_DATA_ITEM.toString());
        }
        DataItemDTO dataItemDTO = dataItemDTOS.get(0);
        if (((DLMSSubDataItemDTO) dataItemDTO).getClassId() == 300) {
            // classId为300 自定义为GPRS AT指令的操作
            handGprsAtCmd(dataItemDTO, task, atomicTask, cosemData);
        } else {
            handleCosemData(dataItemDTO, task, atomicTask, cosemData, meter);
        }
        return 1;
    }

    private void handGprsAtCmd(DataItemDTO dataItemDTO, Task task, AtomicTask atomicTask, CosemData cosemData) {
        // rawData 返回结果为  <Raw Value="2B 46 57 20 56 65 72 73 69 6F 6E 3A 57 53 47 43 3A 43 53 46 30 56 31 2E 30 2D 31 2E 30 2E 31 2E 34 20 2F 32 31 30 37 32 36 0D 0A "/>
        String rawDataValue = cosemData.getValue().replaceAll(" +", "");
        String value = HexUtil.decodeHexStr(rawDataValue);
        if (task.getIsODR()) {
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), value, 600L, true);
        }
    }

    private void handleCosemData(DataItemDTO dataItemDTO, Task task, AtomicTask atomicTask, CosemData cosemData, Meter meter) throws UDISTaskHandlerException {
        ObjectType objectType = ObjectType.forValue(((DLMSSubDataItemDTO) dataItemDTO).getClassId());
        Object result = null;
        switch (objectType) {
            case DATA:
            case REGISTER:
            case EXTENDED_REGISTER:
                result = processRegisterData(task, atomicTask, cosemData, dataItemDTO, meter);
                break;
            case DISCONNECT_CONTROL:
                result = processDisconnectControlData(task, atomicTask, cosemData, dataItemDTO, meter);
                break;
            case ACTION_SCHEDULE:
                result = processClass22Data(task, atomicTask, cosemData, dataItemDTO);
                break;
            case TOKEN_GATEWAY:
                result = processTokenData(task, atomicTask, cosemData, dataItemDTO);
                break;
            default:
                throw new UDISTaskHandlerException(TaskHandlerErrorCode.NO_IMPLEMENTATION_CURRENTLY.toString());
        }

        if (task.getTaskType().equals(TaskType.SwitchMeterPayment.toString())) {
            Map<String, Object> parameterMap = getParameterMap(task, atomicTask);
            Long taskId = MapUtil.getLong(parameterMap, "taskId");
            Long subDataItemId = MapUtil.getLong(parameterMap, "subDataItemId");
            if (isSubTaskGroupLastAtomicTask(task, atomicTask)) {
                assetManagementService.updateStepStatus(taskId, task.getMeterId(), LogModeSwitchHisSub.Step.ReadData, SubTaskStatus.Success.getCode(), null, SystemClock.now() / 1000, null);
            }
            // 入库
            RdModeSwitchData rdModeSwitchData = new RdModeSwitchData();
            rdModeSwitchData.setTaskId(taskId);
            rdModeSwitchData.setSubDataItemId(subDataItemId);
            rdModeSwitchData.setMeterId(meter.getMeterId());
            RdModeSwitchData dbData = rdModeSwitchDataMapper.selectOne(Wrappers.lambdaQuery(rdModeSwitchData));
            if (dbData == null) {
                rdModeSwitchData.setValue(Convert.toStr(result));
                rdModeSwitchDataMapper.insert(rdModeSwitchData);
            } else {
                RdModeSwitchData updateData = new RdModeSwitchData();
                updateData.setValue(Convert.toStr(result));
                rdModeSwitchDataMapper.update(updateData, Wrappers.lambdaUpdate(rdModeSwitchData));
            }
        }
    }

    private Object processClass22Data(Task task, AtomicTask atomicTask, CosemData cosemData, DataItemDTO dataItemDTO) throws UDISTaskHandlerException{
        Object result = null;
        switch (((DLMSSubDataItemDTO) dataItemDTO).getAttributeId()) {
            case 2: // executed_ script
                String executedScriptVal = "";
                if (cosemData.getChild() != null) {
                    String scriptLogicalName = cosemData.getChild().get(0).getValue();
                    Long scriptSelector = Convert.toLong(cosemXmlService.getData(cosemData.getChild().get(1).getType(), cosemData.getChild().get(1).getValue()));
                    executedScriptVal = scriptLogicalName + " , " + scriptSelector;
                }
                if (task.getIsODR()) {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), executedScriptVal, 600L, true);
                }
                break;
            case 3: // type
                Object data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                if (task.getIsODR()) {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), data, 600L, true);
                }
                break;
            case 4: // execution_time 返回 00:00:00 00,FFFF-FF-01 FF;01:00:00 00,FFFF-FF-01 FF
                StringBuilder sb = new StringBuilder();
                if (cosemData.getChild() != null) {
                    for (int i =0 ;i < cosemData.getChild().size(); i++) {
                        if (i > 0) {
                            sb.append(";");
                        }
                        CosemData timeChildData = cosemData.getChild().get(i).getChildAt(0);
                        String timeValue = CustomCosemUtil.parseOctStringTimeWithHundth(timeChildData.getValue());
                        sb.append(timeValue);
                        CosemData dateChildData = cosemData.getChild().get(i).getChildAt(1);
                        String dateValue = CustomCosemUtil.parseOctStringDateWithSPWeek(dateChildData.getValue());
                        sb.append(",").append(dateValue);
                    }
                }
                if (task.getIsODR()) {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), sb.toString(), 600L, true);
                }
                break;
            default:
                throw new UDISTaskHandlerException(TaskHandlerErrorCode.NO_IMPLEMENTATION_CURRENTLY.toString());
        }

        return result;
    }


    private Object processRegisterData(Task task, AtomicTask atomicTask, CosemData cosemData, DataItemDTO dataItemDTO, Meter meter) {
        Object specialData = processSpecialData(task, atomicTask, cosemData, dataItemDTO);
        if (specialData != null) {
            return specialData;
        }

        Object result = null;
        switch (((DLMSSubDataItemDTO) dataItemDTO).getAttributeId()) {
            case 2: // value
                Object data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                if ("OctetString".equalsIgnoreCase(cosemData.getType())) {
                    if (CosemUtils.isDateTimeString(Convert.toStr(data))) {
                        data = DateFormatUtils.format(CosemUtils.parseOctStringDataTime(Convert.toStr(data)), "yyyy-MM-dd HH:mm:ss");
                    } else if (CosemUtils.isLocalDate(Convert.toStr(data))) {
                        data = CosemUtils.parseOctStringDate(Convert.toStr(data));
                    } else if (CosemUtils.isLocalTime(Convert.toStr(data))) {
                        data = CosemUtils.parseOctStringTime(Convert.toStr(data));
                    } else if (CosemUtils.isAsciiHexStr(Convert.toStr(data))) {
                        data = HexUtil.decodeHexStr(Convert.toStr(data));
                    } else if (dataItemDTO.getSubDataItemId() == 1020010106102L) {
                        // Active date of  passive tariff table
                        data = CosemUtils.parseOctStringDataTimeX(Convert.toStr(data));
                    }
                }

                if ("Date".equalsIgnoreCase(cosemData.getType())) {
                    data = CosemUtils.parseOctStringDateX(Convert.toStr(data));
                }

                if ("Array".equalsIgnoreCase(cosemData.getType())) {
                    Preconditions.checkNotNull(meter);
                    data = convertLongToCommaString(cosemData.getChild(), dataItemDTO, meter.getModelId());
                }

                if (task.getIsODR()) {
                    JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
                    String value = Convert.toStr(assetManagementService.convertDataItemValWithUnit(meter.getModelId(), Convert.toLong(dataItemDTO.getSubDataItemId()), Convert.toStr(data), AppName.GUI.toString())[0]);
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), value, 600L, true);
                }
                if (TaskType.WsMdmMeterReading.name().equals(task.getTaskType())) {
                    processVendingReadingResult(task, atomicTask, data, meter, true, "");
                }
                result = data;
                break;
            case 3: // scaler_unit
                Integer scale = Convert.toInt(cosemXmlService.getData(cosemData.getChildAt(0).getType(), cosemData.getChildAt(0).getValue()));
                Integer unitEnum = Convert.toInt(cosemXmlService.getData(cosemData.getChildAt(1).getType(), cosemData.getChildAt(1).getValue()));
                Unit unit = Unit.forValue(unitEnum);
                String scaleResult = String.format("(%s:%s)", unit.getText(), scale);
                if (task.getIsODR()) {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), scaleResult, 600L, true);
                }
                result = scaleResult;
                break;
            case 5: // class 4 (capture_time)
                Object dataCapTime = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                if ("OctetString".equalsIgnoreCase(cosemData.getType())) {
                    if (CosemUtils.isDateTimeString(Convert.toStr(dataCapTime))) {
                        dataCapTime = DateFormatUtils.format(CosemUtils.parseOctStringDataTime(Convert.toStr(dataCapTime)), "yyyy-MM-dd HH:mm:ss");
                    }
                }
                if (task.getIsODR()) {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), dataCapTime, 600L, true);
                }
                if (TaskType.WsMdmMeterReading.name().equals(task.getTaskType())) {
                    processVendingReadingResult(task, atomicTask, dataCapTime, meter, true, "");
                }
                break;
            default:
                log.info("not support currently");
                break;
        }

        return result;
    }

    private String convertLongToCommaString(List<CosemData> child, DataItemDTO dataItemDTO, Long modelId) {
        ScalerUnit scalerUnit = assetManagementService.getScalerUnitByModelIdSubDataItemId(modelId, dataItemDTO.getSubDataItemId());
        List<String> collect = child.stream().map(o -> cosemXmlService.getData(o.getType(), o.getValue())).map(Convert::toStr).
                map(valueStr -> {
                    if (scalerUnit == null) {
                        return valueStr;
                    }
                    BigDecimal val = new BigDecimal(valueStr).multiply(BigDecimal.valueOf(Math.pow(10, scalerUnit.getScaler())));
                    if (scalerUnit.getScaler() < 0) {
                        return val.setScale(-1 * scalerUnit.getScaler().intValue()).toString();
                    }
                    return val.toString();
                }).collect(Collectors.toList());
        return String.join(",", collect);
    }

    private void processVendingReadingResult(Task task, AtomicTask atomicTask, Object data, Meter meter, boolean isSuccess, String failedMessage) {
        Map<String, Object> parameterMap = getParameterMap(task, atomicTask);
        Long subDataItemId = MapUtil.getLong(parameterMap, "subDataItemId");
        String refVale = MapUtil.getStr(parameterMap, "refValue");
        String value = "";
        if (isSuccess) {
            value = Convert.toStr(assetManagementService.convertDataItemValWithUnit(meter.getModelId(), subDataItemId, Convert.toStr(data), AppName.GUI.toString())[0]);
        } else {
            value = failedMessage;
        }
        taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), meter.getCustomerSn() + "_" + refVale, value, Long.valueOf(2 * 60 * 60), true);
        if (isSubTaskGroupLastAtomicTask(task, atomicTask)) {
            List<TaskDataDTO> taskDataDTOS = taskDAO.getAllTaskData(task.getTaskNo());
            TaskResult taskResult = new TaskResult();
            taskResult.setTaskNo(task.getTaskNo());
            taskResult.setResultData(taskDataDTOS);
            taskResult.setMessageId(task.getMessageId());
            // send to adapter
            Map<String, Object> taskMap = JSONUtil.toBean(task.getParamJson(), Map.class);
            String vendingXmlStr = (String) taskMap.get("vendingXmlRequest");
            sendVendingResultToAdapter(VendingParameterMessageDto.ActionType.GetMeterReadings.name(), vendingXmlStr, taskResult, null, "0.0");
        }

    }

    private void sendVendingResultToAdapter(String vendingType, String requestXmlMsg, TaskResult taskResult, String errorMsg, String replyCode) {
        if (StrUtil.isNotEmpty(errorMsg)) {
            log.info(errorMsg);
        }
        JSONObject obj = JSONUtil.createObj();
        obj.set("VendingType", vendingType);
        obj.set("vendingXmlRequest", requestXmlMsg);
        if (StrUtil.isNotEmpty(errorMsg)) {
            obj.set("errorMessage", errorMsg);
        }
        obj.set("replyCode", replyCode);
        if (taskResult != null) {
            obj.set("taskResult", taskResult);
        }

        kafkaTemplate.send(TaskKafkaTopic.TASK_VENDING_RESULT_TO_ADAPTER, JSONUtil.toJsonStr(obj).getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 处理特殊数据项
     *
     * @param task
     * @param atomicTask
     * @param cosemData
     * @param dataItemDTO
     * @return
     */
    private Object processSpecialData(Task task, AtomicTask atomicTask, CosemData cosemData, DataItemDTO dataItemDTO) {
        Object result = null;
        switch (Convert.toStr(dataItemDTO.getSubDataItemId())) {
            case "1020010111102": // Friendly Time 报文 10000B00 需要转成[16:00, 11:00]
                Object data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                result = data;
                if (task.getIsODR()) {
                    String value = CustomCosemUtil.formatFriendTimeStr(Convert.toStr(data));
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), value, 600L, true);
                }
                break;
        }
        return result;
    }

    private Object processTokenData(Task task, AtomicTask atomicTask, CosemData cosemData, DataItemDTO dataItemDTO) {
        Object result = null;
        switch (((DLMSSubDataItemDTO) dataItemDTO).getAttributeId()) {
            case 2: // token
                Object data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), Convert.toStr(data), 600L, true);
                result = data;
                break;
            case 3: // token_time
                data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), CosemUtils.parseOctStringDataTimeX(Convert.toStr(data)), 600L, true);
                result = data;
                break;
            case 4: // token_description
                List<String> tokenDescs = new ArrayList<>();
                if (cosemData.getChild() != null) {
                    for (int i = 0; i < cosemData.getChild().size(); i++) {
                        CosemData childData = cosemData.getChild().get(i);
                        tokenDescs.add(Convert.toStr(cosemXmlService.getData(childData.getType(), childData.getValue())));
                    }
                }
                result = Convert.toStr(tokenDescs);
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), Convert.toStr(tokenDescs), 600L, true);
                break;
            case 5: // token_method
                data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                TokenGateway.TokenDeliveryMethod tokenDeliveryMethod = TokenGateway.TokenDeliveryMethod.getTokenDeliveryMethod(Convert.toInt(data));
                result = Convert.toStr(tokenDeliveryMethod.name());
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), Convert.toStr(tokenDeliveryMethod.name()), 600L, true);
                break;
            case 6: // token_status
                List<CosemData> childrenTokenData = cosemData.getChild();
                if (childrenTokenData.size() == 2) {
                    Integer statusCode = Convert.toInt(cosemXmlService.getData(childrenTokenData.get(0).getType(), childrenTokenData.get(0).getValue()));
                    TokenGateway.StatusCode.getByCode(statusCode);
                    String value = Convert.toStr(TokenGateway.StatusCode.getByCode(statusCode) == null ? "" :
                            TokenGateway.StatusCode.getByCode(statusCode).name());
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), value, 600L, true);
                    result = value;
                } else {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), "", 600L, true);
                }
                break;
            default:
                log.info("not support currently");
                break;
        }

        return result;
    }

    private Object processDisconnectControlData(Task task, AtomicTask atomicTask, CosemData cosemData, DataItemDTO dataItemDTO, Meter meter) {
        Object result = null;
        switch (((DLMSSubDataItemDTO) dataItemDTO).getAttributeId()) {
            case 2: // output_state
                // true false处理成 0(false)或者1(true) 返回给web
                boolean outputState = Boolean.parseBoolean(Convert.toStr(cosemXmlService.getData(cosemData.getType(), cosemData.getValue())));
                if (task.getIsODR()) {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()),
                            outputState ? "1" : "0", 600L, true);
                }
                result = outputState ? "1" : "0";
                if (TaskType.WsMdmMeterReading.name().equals(task.getTaskType())) {
                    processVendingReadingResult(task, atomicTask, result, meter, true, "");
                }
                break;
            case 3: // control_state
            case 4: // output_mode
                // 暂时都返回原值给页面
                Object data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
                if (task.getIsODR()) {
                    taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(dataItemDTO.getSubDataItemId()), data, 600L, true);
                }
                result = data;
                if (TaskType.WsMdmMeterReading.name().equals(task.getTaskType())) {
                    processVendingReadingResult(task, atomicTask, result, meter, true, "");
                }
                break;
            default:
                log.info("not support currently");
                break;
        }
        if (StrUtil.equalsIgnoreCase(task.getTaskType(),TaskType.GetRelayControlMode.name())) {
            assetManagementService.updateLogRelayControl(task.getTaskNo(), meter.getMeterId(), ConfigScheduleTask.ActionType.GET_DEVICE_CONFIG.getType(), SubTaskStatus.Success.getCode(),Convert.toInt(result), null);
        }

        return result;
    }

    @Override
    public int handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("error {}, ", message);
        if (task.getTaskType().equals(TaskType.SwitchMeterPayment.toString())) {
            Map<String, Object> parameterMap = getParameterMap(task, atomicTask);
            Long taskId = MapUtil.getLong(parameterMap, "taskId");
            Long now = SystemClock.now() / 1000;
            assetManagementService.updateStepStatus(taskId, task.getMeterId(), LogModeSwitchHisSub.Step.ReadData, SubTaskStatus.Failed.getCode(), null, now,
                    String.format("handle %s fail, [%s]", OperationName.forId(atomicTask.getOperationId()).getName(), message));
        } else if (StrUtil.equals(TaskType.WsMdmMeterReading.toString(), task.getTaskType())) {
            // Vending接口失败结果处理
            Meter meter = assetManagementService.getMeterById(task.getMeterId());
            processVendingReadingResult(task, atomicTask, null, meter, false, message);
        } else if (StrUtil.equalsIgnoreCase(task.getTaskType(),TaskType.GetRelayControlMode.name())) {
            assetManagementService.updateLogRelayControl(task.getTaskNo(), task.getMeterId(), ConfigScheduleTask.ActionType.GET_DEVICE_CONFIG.getType(), SubTaskStatus.Failed.getCode(),null, message);
        } else {
            Map<String, Object> param = getParameterMap(task, atomicTask);
            Long subDataItemId = Long.valueOf(String.valueOf(param.get("subDataItemId")));
            if (task.getIsODR()) {
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), Convert.toStr(subDataItemId), message, 600L, false);
            }
        }
        return -1;
    }

    private List<DataItemDTO> getModelDataItemCosems(Long modelId, List<Long> dataItemIds, Integer deviceActionTypeCode) {
        ModelDataItemQueryItem modelDataItemQueryItem = new ModelDataItemQueryItem();
        modelDataItemQueryItem.setModelId(modelId);
        modelDataItemQueryItem.setDataItemIds(dataItemIds);
        modelDataItemQueryItem.setDeviceActionType(deviceActionTypeCode);

        return assetManagementService.queryModelDataItemCosem(modelDataItemQueryItem);
    }

    private void removeSetAtomicTaskIfExists(Task task, AtomicTask atomicTask) {
        if (StrUtil.equalsIgnoreCase(TaskType.WsMdmMeterReading.toString(), task.getTaskType())) {
            //失败的话 结束后续所有任务
            AtomicTask disconnectTask = taskDAO.atomicTaskQueuePopReverse(task.getTaskNo());
            String termQueueId = taskDAO.getTerminalTaskListKey(task);
            taskDAO.terminalTaskQueuePop(termQueueId);
            taskDAO.atomicTaskQueueDelete(task.getTaskNo());
            taskDAO.clearTaskProcessingAtomic(task.getTaskNo());
            log.info("remove vending meterReading atomicTask {} ", disconnectTask.getAtomicTaskNo());
        }
    }

}
